module nazo.set;
/**
 * いろんなものの集合
 * License: Public Domain
 */
///Bugs: コンパイラがクラッシュする

/+
static class NumberSet(int skip, bool reverse=false, int add=0){
  static int[] opSlice(int i,int j){
    assert(i<j);
    int[] rv = new int[j-i];
    i*=skip;
    j*=skip;
    for(int n;i<j;i+=skip,n++){
      rv[n]=reverse?-i-add:i+add;
    }
    return rv;
  }
  static int opIndex(int i){
    return i;
  }
}

///0,1,2...
alias NumberSet!(1) IntegerSet;
///0,-1,-2...
alias NumberSet!(1, true) ReverseIntegerSet;
///0,2,4...
alias NumberSet!(2) EvenNumberSet;
///0,-2,-4...
alias NumberSet!(2, true) ReverseEvenNumberSet;
///1,3,5...
alias NumberSet!(2, false, 1) OddNumberSet;
///-1,-3,-5...
alias NumberSet!(2, true, 1) ReverseOddNumberSet;

///$start-$end $start$start-$end$end...
static class StringSet(char start,char end){
  static string[] opSlice(uint i,uint j){
    assert(i<j);
    string[] rv = new string[j-i];
    string a = opIndex(i);
    foreach(inout string v; rv){
      v = a;
      a = next!(start, end)(a);
    }
    return rv;
  }
  static string opIndex(uint i){
    const int n = end-start+1;
    string rv;
    i++;
    while(i>0){
      rv~=(i-1)%n+start;
      i=(i-1)/n;
    }
    rv.reverse;
    return rv;
  }
  private static string next(char start,char end)(string val){
    string rv = val.idup;
    for(int i=val.length-1;i>=0;i--){
      if(val[i] != end){
        rv[i]++;
        return rv;
      }
      rv[i]=start;
    }
    rv.length = rv.length+1;
    rv[1..$] = rv[0..$-1];
    rv[0]=start;
    return rv;
  }
}

///a-z aa-zz aaa-zzz...
alias StringSet!('a','z') AlphabetSet;

import std.stdio;
unittest{
  assert(IntegerSet[0..6] == [0,1,2,3,4,5]);
  assert(ReverseIntegerSet[0..6] == [0,-1,-2,-3,-4,-5]);
  assert(IntegerSet[0..1] == [0]);
  assert(ReverseIntegerSet[0..1] == [0]);
  assert(IntegerSet[-5..6] == [-5,-4,-3,-2,-1,0,1,2,3,4,5]);
  assert(ReverseIntegerSet[-5..6] == [5,4,3,2,1,0,-1,-2,-3,-4,-5]);
  assert(IntegerSet[-5..1] == [-5,-4,-3,-2,-1,0]);
  assert(ReverseIntegerSet[-5..1] == [5,4,3,2,1,0]);
  assert(IntegerSet[0]==0);
  assert(IntegerSet[5]==5);
  assert(IntegerSet[-5]==-5);
  assert(EvenNumberSet[1..3]==[2,4]);
  assert(OddNumberSet[1..3]==[3,5]);
  assert(AlphabetSet[0..1]==["a"[]]);
  assert(AlphabetSet[1..2]==["b"[]]);
  assert(AlphabetSet[99]==AlphabetSet[0..100][$-1]);
}+/
